針對 Lambda 設定,絕大多數人一定碰過 ImportModuleError
所以各位可以跟著以下的情境,開一個一樣的 Lambda 環境逐步操作。
IAD(us-east-1)
Python3.11
import json requests
def lambda_handler(event, context):
# TODO implement
x = requests.get('https://www.ntust.edu.tw/')
print(x.text)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
如果你按照上述情境部署,並且進行測試,可能會報出類似下面的錯誤
{
"errorMessage": "Unable to import module 'lambda_function': No module named 'requests'",
"errorType": "Runtime.ImportModuleError",
"requestId": ".......",
"stackTrace": []
}
這個錯誤的原因在於,在 AWS Lambda python 3.8 Runtime 之後的版本就沒有原生支援 requests 模組,會需要自己添加層(layer)
在 Lambda 中, Layer 是用來存放dependency 或者是模組用的zip 壓縮檔。不同的 Lambda 函數也可以通過 layer 來去共享資料。
一旦你為你的 Lambda 函數新增一個 Layer,Lambda 就會去將你 layer當中的資料放到 Lambda 執行環境中的 /opt
目錄底下。
注意: 每個函數最多只能包含5個 Layer
每個 Layer 當中的模組,隨著你使用 Runtime 的不同,打包 zip檔時會需要遵循不同的檔案結構 [1]。
以 Python 來說 檔案結構可以是:
/opt/python
/opt/python/lib/python3.x/site-packages
而所有 Runtime 都支援以下兩種額外的目錄:
/bin (PATH)
/lib (LD_LIBRARY_PATH)
現在我們就來為 requests 打包成壓縮檔吧
pip install requests --target=./python
這會在你本地當中建立 python/
目錄,並將所需的模組下載到目錄中,請注意這裡的目錄名稱需要與 Runtime 所使用的語言匹配。
zip -r layer.zip python/
去將 python 目錄底下的所有檔案打包至一個 zip檔
為Layer 取名並且在頁面中上傳剛才建立的 layer.zip
,接著選擇 Runtime 以及架構後就可以建立Layer了。
完成後就回到 Lambda 主頁去新增 Layer
新增 Layer 的頁面中選擇 Custom Layer,就可以看到剛剛建立的 Layer了。
這時再度從主控台按下測試,就不會報錯了
或者通過 AWS CLI 去調用
aws lambda invoke \
--cli-binary-format raw-in-base64-out \
--function-name ITHomeLambdaFunction \
--payload '{ "Test": "ITHome" }' \
response.json
去看 CloudWatch 也能收到資料
雖然把吐回來的東西拆成一個一個log entry 很怪XD